package cz.worktracker.controller;

import cz.worktracker.enums.DataSetsEnum;
import cz.worktracker.model.entities.Customer;
import cz.worktracker.model.entities.Invoice;
import cz.worktracker.model.entities.Project;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.annotation.ManagedBean;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.enterprise.context.RequestScoped;
import javax.enterprise.context.SessionScoped;
import javax.faces.context.FacesContext;
import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;
import javax.faces.model.SelectItem;
import javax.inject.Inject;
import javax.inject.Named;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Transaction;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;


/**
 * InvoiceManager
 * Správa faktur
 * @since 2010-05-01
 * @author kyjovsky
 */
@ManagedBean
@RequestScoped
@Named
public class InvoiceManager extends AbstractManager
        implements Serializable {

    private static final long serialVersionUID = 1L;
    private Invoice invoice;
    private Customer customer;
    private Project project;
    private static final String NAV_DETAIL = "detail";
    private static final String NAV_REDIRECT = "?faces-redirect=true";

    /* TABULKA */
    private AbstractPaginator paginator;
    private DataModel dataModel;
    private DataSetsEnum DSEnum;
    private int rowsPerPage = DSEnum.ITEMS_PER_PAGE_DEFAULT.getValue();
    private String sortByField = DSEnum.SORT_BY_FIELD.getStringValue();
    private String sortDirection = DSEnum.SORT_DIRECTION.getStringValue();
    /* TABULKA */

    @PostConstruct
    public void construct() {
        init();
    }

    @PreDestroy
    public void destroy() {
        invoice = null;
        customer = null;
        project = null;
        paginator = null;
        dataModel = null;
    }

    @Inject ProjectManager projectManager;
    @Inject CustomerManager customerManager;

    private void init() {
        invoice = new Invoice();
        invoice.setIdProject(-1);
    }

    public boolean getNewInvoice() {
        init();
        return true;
    }

    public ArrayList getSelectProjectsList() {
        if (customer != null) {
            ArrayList list = null;
            try {
                Transaction tx = getSession().beginTransaction();
                //          System.out.println(customer.getId());
                String hql = "from Project as project where project.idCustomer = '" + customer.getId() + "'"
                        + " and project.isActive = 'y'";
                Query query = getSession().createQuery(hql);

                list = new ArrayList();
                Project tempProject;

                for (int i = 0; i < query.list().size(); i++) {
                    tempProject = (Project) query.list().get(i);
                    list.add(new SelectItem(tempProject.getId(), tempProject.getName()));
                    tempProject = null;
                }
                tx.commit();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return list;
        }
        return null;
    }

    public Integer getCustomerId() {
        return 0;
    }

    public void setCustomerId(Integer idCustomer) {
        if (idCustomer > 0) {
            try {
                Transaction tx = getSession().beginTransaction();
                String hql = "from Customer as customer where customer.id = '" + idCustomer + "'";
                Query query = getSession().createQuery(hql);

                customer = (Customer) query.list().get(0);
                tx.commit();

            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            init();
            customer = null;
            project = null;
        }
    }

    public Integer getProjectId() {
        return 0;
    }

    public void setProjectId(Integer idProject) {
        System.out.println("CUSTOMER:" + customer.getId().toString());
        System.out.println("PROJECT:" + idProject.toString());
        if (idProject > 0) {
            try {
                Transaction tx = getSession().beginTransaction();
                String hql = "from Project as project where project.id = '" + idProject + "'";
                Query query = getSession().createQuery(hql);

                project = (Project) query.list().get(0);
                tx.commit();

                invoice.setIdProject(idProject);

                tx = getSession().beginTransaction();
                hql = "from Invoice as invoice where invoice.idProject = '" + idProject + "'";
                query = getSession().createQuery(hql);

                Invoice tmpInvoice;
                Date lastDate;

                for (int i = 0; i < query.list().size(); i++) {
                    tmpInvoice = (Invoice) query.list().get(i);
                    if (tmpInvoice.getRateType().equals("p")) {
                        project = null;
                    }
                }

                tx.commit();

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public boolean getIsInvoiceData() {
        return true;
    }

    public boolean getIsCustomer() {

        if (customer == null) {
            return false;
        }

        return true;
    }

    public Invoice getInvoice() {
        return invoice;
    }

    public void setInvoice(Invoice invoice) {
        this.invoice = invoice;
    }

    public Customer getCustomer() {
        return customer;
    }

    public void setCustomer(Customer customer) {
        this.customer = customer;
    }

    public Project getProject() {
        return project;
    }

    public void setProject(Project project) {
        this.project = project;
    }

    /**
     * Prepares dataModel.
     * @return Hell I really want to know.
     */
    public String prepareDataModel() {
        resetDataModel();
        return NAV_DETAIL + NAV_REDIRECT;
    }

    /**
     * Method nulls reference of dataModel.
     */
    public void resetDataModel() {
        dataModel = null;
    }

    /**
     * Method nulls reference of paginator.
     */
    public void resetPagination() {
        paginator = null;
    }

    /**
     * Returns page switcher and override abstract methods from AbstractPaginator.
     * @return Paginator object.
     */
    public AbstractPaginator getPaginator() {
        if (paginator == null) {
            paginator = new AbstractPaginator(rowsPerPage) {

                /*
                 * While creating a new instance we have to implement abstract
                 * methods defined in AbstractPaginator class.
                 */
                @Override
                public int getItemsCount() {
                    return getInvoicesCount();
                }

                @Override
                public DataModel createPageDataModel() {
                    List<Invoice> list = new ArrayList();

                    try {
                        ArrayList<Integer> projectIds = projectManager.getProjectIds();
                        for (int i = 0; i < projectIds.size(); i++) {
                            Transaction tx = getSession().beginTransaction();
                            Criteria ct = getSession().createCriteria(Invoice.class);
                            ct.add(Restrictions.eq("idProject", projectIds.get(i)));
                            for (int j = 0; j < ct.list().size(); j++) {
                                list.add((Invoice) ct.list().get(j));
                            }
                            tx.commit();
                            System.out.println("FOR" + i + " - " + projectIds.get(i));
                        }

                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                    return (new ListDataModel(list));
                }
            };
        }
        return paginator;
    }

    /**
     * Returns count of records returned to view.
     * @return int
     */
    public int getRowsPerPage() {
        return rowsPerPage;
    }

    /**
     * Sets count of records returned to view.
     * @param rowsPerPage
     */
    public void setRowsPerPage(int rowsPerPage) {
        this.rowsPerPage = rowsPerPage;

        resetDataModel();
        resetPagination();
    }

    /**
     * Returns DataModel for dataTable.
     * @return DataModel for dataTable.
     */
    public DataModel getList() {
        if (dataModel == null) {
            dataModel = getPaginator().createPageDataModel();
        }

        return dataModel;
    }

    /**
     * Next page.
     */
    public void next() {
        System.out.println(">> last >> " + getPaginator().getActualPage());
        getPaginator().nextPage();
        System.out.println(">> last 2 >> " + getPaginator().getActualPage());
        resetDataModel();
    }

    /**
     * Last page.
     */
    public void last() {
        getPaginator().lastPage();
        resetDataModel();
    }

    /**
     * Previous page.
     */
    public void previous() {
        System.out.println(">> prev >> " + getPaginator().getActualPage());
        getPaginator().previousPage();
        System.out.println(">> prev 2 >> " + getPaginator().getActualPage());
        resetDataModel();
    }

    /**
     * First page.
     */
    public void first() {
        getPaginator().firstPage();
        resetDataModel();
    }

    /**
     * Increments count of items per page.
     */
    public void more() {
        setRowsPerPage(getRowsPerPage() + DSEnum.ITEMS_PER_PAGE_INCREMENT.getValue());

        resetPagination();
        resetDataModel();
    }

    /**
     * * Decrements count of items per page.
     */
    public void less() {
        setRowsPerPage(getRowsPerPage() - DSEnum.ITEMS_PER_PAGE_INCREMENT.getValue());

        resetPagination();
        resetDataModel();
    }

    /**
     * Retrieves sort params through context and initiates sort.
     */
    public void sort() {
        /**
         * Try to gain params send by <f:param />
         */
        FacesContext context = FacesContext.getCurrentInstance();
        Map requestMap = context.getExternalContext().getRequestParameterMap();
        setSortByField((String) requestMap.get("by"));
        setSortDirection((String) requestMap.get("order"));

        resetPagination();
        resetDataModel();

    }

    /**
     * Returns projects count.
     * @return int means projects count.
     */
    public int getInvoicesCount() {
        ArrayList<Integer> projectIds = projectManager.getProjectIds();
        int countAll = 0;
        
        for (int i = 0; i < projectIds.size(); i++) {
            Transaction tx = getSession().beginTransaction();
            String hql = "select count(*) from Invoice as invoice where invoice.idProject = '" + projectIds.get(i) + "'";
            int count = ((Long) (getSession().createQuery(hql).iterate().next())).intValue();
            tx.commit();
            countAll += count;
        }
        System.out.println("GetInvoicesCount: " + countAll);
        return countAll;
    }

    /**
     * Returns count of records in Data Model.
     * @return int
     */
    public int getDataModelRecordsCount() {

        if( getList() != null ) {
            return getList().getRowCount();
        }

        return 0;
    }    

    /**
     * Returns field name in JPA entity according which sorting will be provided.
     * @return String
     */
    public String getSortByField() {
        return sortByField;
    }

    /**
     * Sets field name in JPA entity according which sorting will be provided.
     * @param sortByField
     */
    public void setSortByField(String sortByField) {
        this.sortByField = sortByField;
    }

    /**
     * Returns sort direction (ascending: asc; descending desc).
     * @return String
     */
    public String getSortDirection() {
        return sortDirection;
    }

    /**
     * Sets sort direction (ascending: asc; descending desc).
     * @param sortDirection
     */
    public void setSortDirection(String sortDirection) {
        this.sortDirection = sortDirection;
    }

    /**
     * Based on actual row, method returns Customer name
     * @return String
     */
    public String getRowCustomerName() {

        Invoice tmpInvoice = (Invoice) dataModel.getRowData();
        int idProject = tmpInvoice.getIdProject();

        if( idProject > 0 ) {
            Transaction tx = getSession().beginTransaction();
            String hql = "from Project as project where project.id = '"+ idProject +"'";
            Query query = getSession().createQuery( hql );
            query.setMaxResults( 1 );
            Project tmpProject =  (Project) query.uniqueResult();
            tx.commit();

            int idCustomer = tmpProject.getIdCustomer();

            if( idCustomer > 0 ) {
                tx = getSession().beginTransaction();
                hql = "from Customer as customer where customer.id = '"+ idCustomer +"'";
                query = getSession().createQuery( hql );
                query.setMaxResults( 1 );
                Customer tmpCustomer =  (Customer) query.uniqueResult();
                tx.commit();
                return tmpCustomer.getName();
            }

            return "-- internal --";
        }

        return null;
    }

    /**
     * Based on actual row, method returns Customer name
     * @return String
     */
    public String getRowProjectName() {
        // Project tmpProject = (Project) getList().getRowData();
        Invoice tmpInvoice = (Invoice) dataModel.getRowData();
        int idProject = tmpInvoice.getIdProject();

        if( idProject > 0 ) {
            Transaction tx = getSession().beginTransaction();
            String hql = "from Project as project where project.id = '"+ idProject +"'";
            Query query = getSession().createQuery( hql );
            query.setMaxResults( 1 );
            Project tmpProject =  (Project) query.uniqueResult();
            tx.commit();
            return tmpProject.getName();
        }

        return null;
    }

     public String detail() {

        invoice = (Invoice) getList().getRowData();
        resetDataModel();
        System.out.println("INVOICE: " + invoice.getInvoiceNumber());
        return NAV_DETAIL + NAV_REDIRECT;
     }


     public String projectDetail() {
        // Project tmpProject = (Project) getList().getRowData();
        Invoice tmpInvoice = (Invoice) dataModel.getRowData();
        int idProject = tmpInvoice.getIdProject();

        if( idProject > 0 ) {
            Transaction tx = getSession().beginTransaction();
            String hql = "from Project as project where project.id = '"+ idProject +"'";
            Query query = getSession().createQuery( hql );
            query.setMaxResults( 1 );
            projectManager.setProject((Project) query.uniqueResult());
            tx.commit();
            return "/user/project/detail" + NAV_REDIRECT;
        }

        return null;

     }

     public String customerDetail() {
        Invoice tmpInvoice = (Invoice) dataModel.getRowData();
        int idProject = tmpInvoice.getIdProject();

        if( idProject > 0 ) {
            Transaction tx = getSession().beginTransaction();
            String hql = "from Project as project where project.id = '"+ idProject +"'";
            Query query = getSession().createQuery( hql );
            query.setMaxResults( 1 );
            Project tmpProject =  (Project) query.uniqueResult();
            tx.commit();

            int idCustomer = tmpProject.getIdCustomer();

            if( idCustomer > 0 ) {
                tx = getSession().beginTransaction();
                hql = "from Customer as customer where customer.id = '"+ idCustomer +"'";
                query = getSession().createQuery( hql );
                query.setMaxResults( 1 );
                customerManager.setCustomer((Customer) query.uniqueResult());
                tx.commit();
                return "/user/customer/detail" + NAV_REDIRECT;
            }

            return null;
        }

        return null;
     }

    public String getStringDate(Date date) {
      String day = ((Integer) date.getDate()).toString();
      String month = ((Integer) (date.getMonth()+1)).toString();
      String year = ((Integer) (date.getYear() + 1900)).toString();


      return day + "." + month + "." + year;
    }

    public String getDateOfIssueString() {
        Invoice tmpInvoice = (Invoice) dataModel.getRowData();
        return getStringDate(tmpInvoice.getDateOfIssue());
    }

    public String getIsPaidString() {
        Invoice tmpInvoice = (Invoice) dataModel.getRowData();
        if (tmpInvoice.getIsPaid().equals("y")) return "ANO";
        else return "NE";
    }

     public String showList() {
        resetDataModel();
        return "/user/invoice/list" + NAV_REDIRECT;
     }

}
